import { createUpdateId, EChart, TEChartDatasetInfo, TEChartOptions, TEchartUpdateInfo, TUpdateInfoActionType } from "@/models/reactiveComponent";
import { set, mergeWith, clone } from "lodash-es";
import { createSqlQueryMappingRunner } from "@/core/jsCodeRunner";

import { TEchartEventParams, TEchartInstance, TPerformType, TServices } from "./types";
import * as utils from "./utils";
import { TCatDimFieldCache, TDataGroupValueCache, TDbQuery } from "./utils";
import { getParamValue } from "./chartEventHanlder";
import { refixOptions } from "./optionsRefix.ts";
import { createFunc } from "./jsCodeRunner";

export type TChartCreator = ReturnType<typeof create>

export function create(model: EChart, infoIndex: number, performType: TPerformType, services: TServices) {
    const chartInfo = model.chartInfos[infoIndex]
    const options = chartInfo.options

    const catDimFieldCache = utils.createCatDimFieldCache()
    const dataGroupValueCache = utils.createDataGroupValueCache()

    const hasClickInfo = utils.hasClickInfo(chartInfo)

    chartInfo.jsCodes.forEach(info => {
        const func = createFunc(info.code)
        set(options, info.path, func)
    })

    function useOptions() {

        chartInfo.datasetInfos.forEach(info => {
            const sqlQuery = services.utils.createSqlQuery(createUpdateId(model, infoIndex), info.sqlInfo.sql)
            const rows = sqlQuery.query()
            const mapRunner = createSqlQueryMappingRunner(info.sqlInfo.jsMap, info.sqlInfo.type)
            const resValues = mapRunner.map(rows)
            set(options, info.path, resValues)
        })


        const copyMergeSettings = clone(chartInfo.postMergeSettings)

        if (copyMergeSettings.hasOwnProperty('series')) {

            if (options.hasOwnProperty('series') && Array.isArray(options.series)) {

                options.series.forEach(s => {
                    mergeWith(s, copyMergeSettings.series)
                })

            }

            delete copyMergeSettings.series
        }

        mergeWith(options, copyMergeSettings)



        switch (performType.value) {
            case 'forward':
                // in the chain downstream
                utils.drillEndPosCommon(options, dataGroupValueCache)
                break;
            case 'back':
                //be in the chain upstream

                // utils.setItemGroup(options, catDimFieldCache)
                break;
            default:
                break;
        }


        refixOptions(options)

        // optionsHandler(info, options, query, catDimFieldCache, dataGroupValueCache, performType)
        return options
    }

    function removeFilter() {

        chartInfo.updateInfos.forEach(info => {
            const chartOptId = createUpdateId(model, infoIndex)
            services.dataset.removeFilters(chartOptId, info.table)
        })

    }

    function addFilter(eventParams: TEchartEventParams, actionType: TUpdateInfoActionType) {
        const valueGetter = (info: TEchartUpdateInfo) => {
            return getParamValue(eventParams, info)
        }
        return utils.updateFilters(chartInfo, actionType, valueGetter, model, infoIndex, services);
    }

    function drillStartPos(echartIns: TEchartInstance) {
        switch (performType.value) {
            case 'forward':
                utils.drillStartPosForwardCommon(echartIns)
                break;
            case 'back':
                utils.drillStartPosBackCommon(echartIns, dataGroupValueCache)
                break;
            default:
                break;
        }
    }



    function setDataGroupValue(value: string) {
        dataGroupValueCache.setValue(value)
    }

    return {
        useOptions,
        addFilter,
        removeFilter,
        drillStartPos,
        setDataGroupValue,
        getValueFromParams: getParamValue,
        hasClickInfo,
    }

}










// , drillType: Ref<"next" | "back">
function optionsHandler(
    info: TEChartDatasetInfo,
    options: TEChartOptions,
    query: TDbQuery,
    catDimFieldCache: TCatDimFieldCache,
    dataGroupValueCache: TDataGroupValueCache,
    performType: TPerformType,
) {

    const encodeFn = (fields: string[], curIdx: number) => {
        let x = fields[0]
        let y = fields[curIdx]

        if (options['yAxis'][0]["type"] === 'category') {
            const temp = x
            x = y
            y = temp
        }

        catDimFieldCache.setItemGroupField(x)

        return {
            x,
            y,
        }
    }

    const postOptionsHandler = (options: TEChartOptions) => {

        switch (performType.value) {
            case 'forward':
                // in the chain downstream
                utils.drillEndPosCommon(options, dataGroupValueCache)
                break;
            case 'back':
                //be in the chain upstream

                utils.setItemGroup(options, catDimFieldCache)
                break;
            default:
                break;
        }

    }

    utils.normalOptionsHandler(info, options, query, encodeFn, postOptionsHandler)
}